package com.htg.tdtwebapi;

import com.google.gson.Gson;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TdtApiSearch extends TdtWebApi {

    public static final String url = "http://api.tianditu.gov.cn/v2/search";

    public TdtApiSearch(String key) {
        super(key);
    }


    /**
     * @param keyWord   搜索的关键字
     * @param specify   指定行政区的国标码（行政区划编码表）严格按照行政区划编码表中的（名称，gb码） 下载行政区划编码表。9位国标码，如：北京：156110000或北京。
     * @param queryType 服务查询类型参数 12：行政区划区域搜索服务。
     * @param start     返回结果起始位（用于分页和缓存）默认0 0-300，表示返回结果的起始位置
     * @param count     返回的结果数量（用于分页和缓存） 1-300，返回结果的条数
     * @param dataTypes 数据分类（分类编码表） 下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show      返回poi结果信息类别  取值为1，则返回基本poi信息； 取值为2，则返回详细poi信息
     * @throws Exception
     */
    public String searchRegion(String keyWord, String specify, String queryType, String start, String count, String dataTypes, String show) throws Exception {
        //
        boolean legal = isParamsLegal(keyWord, specify, queryType, start, count);
        if (!legal)
            throw new Exception("keyWord specify queryType start count 为必填参数 不能为null 也不能为空串");
        //
        Map<String, Object> params = new HashMap<>();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("keyWord", keyWord);
        jsonObject.put("queryType", queryType);
        jsonObject.put("start", start);
        jsonObject.put("count", count);
        jsonObject.put("specify", specify);
        if (isParamLegal(dataTypes)) {
            jsonObject.put("dataTypes", dataTypes);
        }
        if (isParamLegal(show)) {
            jsonObject.put("show", show);
        }
        params.put("postStr", jsonObject.toString());
        params.put("type", "query");
        params.put("tk", key);
        String response = get(url, params);
        return response;
    }

    /**
     * @param keyWord   搜索的关键字
     * @param specify   指定行政区的国标码（行政区划编码表）严格按照行政区划编码表中的（名称，gb码） 下载行政区划编码表。9位国标码，如：北京：156110000或北京。
     * @param queryType 服务查询类型参数 12：行政区划区域搜索服务。
     * @param start     返回结果起始位（用于分页和缓存）默认0 0-300，表示返回结果的起始位置
     * @param count     返回的结果数量（用于分页和缓存） 1-300，返回结果的条数
     * @param dataTypes 数据分类（分类编码表） 下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show      返回poi结果信息类别  取值为1，则返回基本poi信息； 取值为2，则返回详细poi信息
     * @throws Exception
     */
    public List<Poi> searchRegion2(String keyWord, String specify, String queryType, String start, String count, String dataTypes, String show) throws Exception {
        String response = searchRegion(keyWord, specify, queryType, start, count, dataTypes, show);
        return response2Pois(response);
    }


    /**
     * @param keyWord   搜索的关键字
     * @param mapBound  地图视野范围(“minx,miny,maxx,maxy”) -180,-90至180,90。
     * @param level     目前查询的级别	 1-18级
     * @param queryType 服务查询类型参数	2：视野内搜索
     * @param start     返回结果起始位（用于分页和缓存）默认0  0-300，表示返回结果的起始位置。
     * @param count     返回的结果数量（用于分页和缓存） 1-300，返回结果的条数。
     * @param dataTypes 数据分类（分类编码表） 下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show      返回poi结果信息类别	 取值为1，则返回基本poi信息； 取值为2，则返回详细poi信息
     * @return
     */
    public String searchInVision(String keyWord, String mapBound, String level, String queryType, String start, String count, String dataTypes, String show) throws Exception {
        //
        boolean legal = isParamsLegal(keyWord, mapBound, level, queryType, start, count);
        if (!legal)
            throw new Exception("keyWord,mapBound,level,queryType,start,count 为必填参数 不能为null 也不能为空串");
        //
        Map<String, Object> params = new HashMap<>();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("keyWord", keyWord);
        jsonObject.put("mapBound", mapBound);
        jsonObject.put("level", level);
        jsonObject.put("queryType", queryType);
        jsonObject.put("start", start);
        jsonObject.put("count", count);
        if (isParamLegal(dataTypes)) {
            jsonObject.put("dataTypes", dataTypes);
        }
        if (isParamLegal(show)) {
            jsonObject.put("show", show);
        }
        params.put("postStr", jsonObject.toString());
        params.put("type", "query");
        params.put("tk", key);
        String response = get(url, params);
        return response;
    }


    /**
     * @param keyWord   搜索的关键字
     * @param mapBound  地图视野范围(“minx,miny,maxx,maxy”) -180,-90至180,90。
     * @param level     目前查询的级别	 1-18级
     * @param queryType 服务查询类型参数	2：视野内搜索
     * @param start     返回结果起始位（用于分页和缓存）默认0  0-300，表示返回结果的起始位置。
     * @param count     返回的结果数量（用于分页和缓存） 1-300，返回结果的条数。
     * @param dataTypes 数据分类（分类编码表） 下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show      返回poi结果信息类别	 取值为1，则返回基本poi信息； 取值为2，则返回详细poi信息
     * @return
     */
    public List<Poi> searchInVision2(String keyWord, String mapBound, String level, String queryType, String start, String count, String dataTypes, String show) throws Exception {
        //
        String response = searchInVision(keyWord, mapBound, level, queryType, start, count, dataTypes, show);
        return response2Pois(response);
    }


    /**
     * @param keyWord     搜索的关键字
     * @param queryRadius 查询半径	单位:米 （10公里内）
     * @param pointLonlat 点坐标	 中心点，经纬度坐标
     * @param queryType   服务查询类型参数	3：周边搜索服务。
     * @param start       返回结果起始位（用于分页和缓存）默认0  0-300，表示返回结果的起始位置。
     * @param count       返回的结果数量（用于分页和缓存） 1-300，返回结果的条数。
     * @param dataTypes   数据分类（分类编码表）  下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show        返回poi结果信息类别	 取值为1，则返回基本poi信息；取值为2，则返回详细poi信息
     * @return
     */
    public String searchNear(String keyWord, String queryRadius, String pointLonlat, String queryType, String start, String count, String dataTypes, String show) throws Exception {
        //
        boolean legal = isParamsLegal(keyWord, queryRadius, pointLonlat, queryType, start, count);
        if (!legal)
            throw new Exception("keyWord,queryRadius,pointLonlat,queryType,start,count 为必填参数 不能为null 也不能为空串");
        //
        Map<String, Object> params = new HashMap<>();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("keyWord", keyWord);
        jsonObject.put("queryRadius", queryRadius);
        jsonObject.put("pointLonlat", pointLonlat);
        jsonObject.put("queryType", queryType);
        jsonObject.put("start", start);
        jsonObject.put("count", count);
        if (isParamLegal(dataTypes)) {
            jsonObject.put("dataTypes", dataTypes);
        }
        if (isParamLegal(show)) {
            jsonObject.put("show", show);
        }
        params.put("postStr", jsonObject.toString());
        params.put("type", "query");
        params.put("tk", key);
        String response = get(url, params);
        return response;
    }


    /**
     * @param keyWord     搜索的关键字
     * @param queryRadius 查询半径	单位:米 （10公里内）
     * @param pointLonlat 点坐标	 中心点，经纬度坐标
     * @param queryType   服务查询类型参数	3：周边搜索服务。
     * @param start       返回结果起始位（用于分页和缓存）默认0  0-300，表示返回结果的起始位置。
     * @param count       返回的结果数量（用于分页和缓存） 1-300，返回结果的条数。
     * @param dataTypes   数据分类（分类编码表）  下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show        返回poi结果信息类别	 取值为1，则返回基本poi信息；取值为2，则返回详细poi信息
     * @return
     */
    public List<Poi> searchNear2(String keyWord, String queryRadius, String pointLonlat, String queryType, String start, String count, String dataTypes, String show) throws Exception {
        //
        String response = searchNear(keyWord, queryRadius, pointLonlat, queryType, start, count, dataTypes, show);
        return response2Pois(response);
    }


    /**
     * @param keyWord   搜索的关键字
     * @param polygon   多边形范围数据(经纬度坐标对)   经度和纬度用","分割，首尾坐标对需相同。实例(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x1,y1)
     * @param queryType 服务查询类型参数	10：多边形搜索服务。
     * @param start     返回结果起始位（用于分页和缓存）默认0     0-300，表示返回结果的起始位置。
     * @param count     返回的结果数量（用于分页和缓存）	1-300，返回结果的条数。
     * @param dataTypes 数据分类（分类编码表）	下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show      返回poi结果信息类别	取值为1，则返回基本poi信息； 取值为2，则返回详细poi信息
     * @return
     */
    public String searchPolygon(String keyWord, String polygon, String queryType, String start, String count, String dataTypes, String show) throws Exception {
        //
        boolean legal = isParamsLegal(keyWord, polygon, queryType, start, count);
        if (!legal)
            throw new Exception("keyWord,polygon,queryType,start,count 为必填参数 不能为null 也不能为空串");
        //
        Map<String, Object> params = new HashMap<>();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("keyWord", keyWord);
        jsonObject.put("polygon", polygon);
        jsonObject.put("queryType", queryType);
        jsonObject.put("start", start);
        jsonObject.put("count", count);
        if (isParamLegal(dataTypes)) {
            jsonObject.put("dataTypes", dataTypes);
        }
        if (isParamLegal(show)) {
            jsonObject.put("show", show);
        }
        params.put("postStr", jsonObject.toString());
        params.put("type", "query");
        params.put("tk", key);
        String response = get(url, params);
        return response;
    }


    /**
     * @param keyWord   搜索的关键字
     * @param polygon   多边形范围数据(经纬度坐标对)   经度和纬度用","分割，首尾坐标对需相同。实例(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x1,y1)
     * @param queryType 服务查询类型参数	10：多边形搜索服务。
     * @param start     返回结果起始位（用于分页和缓存）默认0     0-300，表示返回结果的起始位置。
     * @param count     返回的结果数量（用于分页和缓存）	1-300，返回结果的条数。
     * @param dataTypes 数据分类（分类编码表）	下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show      返回poi结果信息类别	取值为1，则返回基本poi信息； 取值为2，则返回详细poi信息
     * @return
     */
    public List<Poi> searchPolygon2(String keyWord, String polygon, String queryType, String start, String count, String dataTypes, String show) throws Exception {
        //
        String response = searchPolygon(keyWord, polygon, queryType, start, count, dataTypes, show);
        return response2Pois(response);
    }


    /**
     * @param specify   指定行政区的国标码（行政区划编码表）严格按照行政区划编码表中的（名称，gb码）	下载行政区划编码表。9位国标码，如：北京：156110000。
     * @param mapBound  查询的地图范围(“minx,miny,maxx,maxy”)	-180,-90至180,90。
     * @param queryType 服务查询类型参数	13:分类搜索服务。
     * @param start     返回结果起始位（用于分页和缓存）默认0	    0-300，表示返回结果的起始位置。
     * @param count     返回的结果数量（用于分页和缓存）	1-300，返回结果的条数。
     * @param dataTypes 数据分类（分类编码表）	下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show      返回poi结果信息类别	取值为1，则返回基本poi信息； 取值为2，则返回详细poi信息
     * @return
     */
    public String searchDataClassification(String specify, String mapBound, String queryType, String start, String count, String dataTypes, String show) throws Exception {
        //
        boolean legal = isParamsLegal(specify, queryType, start, count);
        if (!legal)
            throw new Exception("specify,queryType, start, count 为必填参数 不能为null 也不能为空串");
        //
        Map<String, Object> params = new HashMap<>();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("specify", specify);
        if (isParamLegal(mapBound)) {
            jsonObject.put("mapBound", mapBound);
        }
        jsonObject.put("queryType", queryType);
        jsonObject.put("start", start);
        jsonObject.put("count", count);
        if (isParamLegal(dataTypes)) {
            jsonObject.put("dataTypes", dataTypes);
        }
        if (isParamLegal(show)) {
            jsonObject.put("show", show);
        }
        params.put("postStr", jsonObject.toString());
        params.put("type", "query");
        params.put("tk", key);
        String response = get(url, params);
        return response;
    }


    /**
     * @param specify   指定行政区的国标码（行政区划编码表）严格按照行政区划编码表中的（名称，gb码）	下载行政区划编码表。9位国标码，如：北京：156110000。
     * @param mapBound  查询的地图范围(“minx,miny,maxx,maxy”)	-180,-90至180,90。
     * @param queryType 服务查询类型参数	13:分类搜索服务。
     * @param start     返回结果起始位（用于分页和缓存）默认0	    0-300，表示返回结果的起始位置。
     * @param count     返回的结果数量（用于分页和缓存）	1-300，返回结果的条数。
     * @param dataTypes 数据分类（分类编码表）	下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show      返回poi结果信息类别	取值为1，则返回基本poi信息； 取值为2，则返回详细poi信息
     * @return
     */
    public List<Poi> searchDataClassification2(String specify, String mapBound, String queryType, String start, String count, String dataTypes, String show) throws Exception {
        //
        String response = searchDataClassification(specify, mapBound, queryType, start, count, dataTypes, show);
        return response2Pois(response);
    }


    /**
     * @param keyWord   搜索的关键字
     * @param mapBound  查询的地图范围(“minx,miny,maxx,maxy”)                                                                                      -180,-90至180,90。
     * @param level     目前查询的级别                                                                                                             1-18级
     * @param specify   指定行政区的国标码（行政区划编码表）严格按照行政区划编码表中的（名称，gb码）。如指定的行政区划编码是省以上级别则返回是统计数据（不包括直辖市）    下载行政区划编码表。9位国标码，如：北京：156110000或北京。
     * @param queryType 搜索类型                                                                                                                  1:普通搜索（含地铁公交） 7：地名搜索
     * @param start     返回结果起始位（用于分页和缓存）默认0                                                                                          0-300，表示返回结果的起始位置。
     * @param count     返回的结果数量（用于分页和缓存）                                                                                               1-300，返回结果的条数。
     * @param dataTypes 数据分类（分类编码表）                                                                                                     下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show      返回poi结果信息类别                                                                                                         取值为1，则返回基本poi信息； 取值为2，则返回详细poi信息
     * @return
     */
    public String searchCommon(String keyWord, String mapBound, String level, String specify, String queryType, String start, String count, String dataTypes, String show) throws Exception {
        //
        boolean legal = isParamsLegal(keyWord, mapBound, level, queryType, start, count);
        if (!legal)
            throw new Exception("keyWord,mapBound,level, queryType, start, count为必填参数 不能为null 也不能为空串");
        //
        Map<String, Object> params = new HashMap<>();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("keyWord", keyWord);
        jsonObject.put("mapBound", mapBound);
        jsonObject.put("level", level);
        if (isParamLegal(specify)) {
            jsonObject.put("specify", specify);
        }
        jsonObject.put("queryType", queryType);
        jsonObject.put("start", start);
        jsonObject.put("count", count);
        if (isParamLegal(dataTypes)) {
            jsonObject.put("dataTypes", dataTypes);
        }
        if (isParamLegal(show)) {
            jsonObject.put("show", show);
        }
        params.put("postStr", jsonObject.toString());
        params.put("type", "query");
        params.put("tk", key);
        String response = get(url, params);
        return response;
    }


    /**
     * @param keyWord   搜索的关键字
     * @param mapBound  查询的地图范围(“minx,miny,maxx,maxy”)                                                                                      -180,-90至180,90。
     * @param level     目前查询的级别                                                                                                             1-18级
     * @param specify   指定行政区的国标码（行政区划编码表）严格按照行政区划编码表中的（名称，gb码）。如指定的行政区划编码是省以上级别则返回是统计数据（不包括直辖市）    下载行政区划编码表。9位国标码，如：北京：156110000或北京。
     * @param queryType 搜索类型                                                                                                                  1:普通搜索（含地铁公交） 7：地名搜索
     * @param start     返回结果起始位（用于分页和缓存）默认0                                                                                          0-300，表示返回结果的起始位置。
     * @param count     返回的结果数量（用于分页和缓存）                                                                                               1-300，返回结果的条数。
     * @param dataTypes 数据分类（分类编码表）                                                                                                     下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show      返回poi结果信息类别                                                                                                         取值为1，则返回基本poi信息； 取值为2，则返回详细poi信息
     * @return
     */
    public List<Poi> searchCommon2(String keyWord, String mapBound, String level, String specify, String queryType, String start, String count, String dataTypes, String show) throws Exception {
        //
        String response = searchCommon(keyWord, mapBound, level, specify, queryType, start, count, dataTypes, show);
        return response2Pois(response);
    }


    /**
     * @param keyWord   搜索的关键字
     * @param specify   指定行政区的国标码（行政区划编码表）严格按照行政区划编码表中的（名称，gb码）	下载行政区划编码表。9位国标码，如：北京：156110000。
     * @param queryType 服务查询类型参数	14：统计搜索服务。
     * @param dataTypes 数据分类（分类编码表）	下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show      返回poi结果信息类别	取值为1，则返回基本poi信息；取值为2，则返回详细poi信息
     * @return
     */
    public String searchStatistics(String keyWord, String specify, String queryType, String dataTypes, String show) throws Exception {
//
        boolean legal = isParamsLegal(keyWord, specify, queryType);
        if (!legal)
            throw new Exception("keyWord,specify, queryType为必填参数 不能为null 也不能为空串");
        //
        Map<String, Object> params = new HashMap<>();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("keyWord", keyWord);
        jsonObject.put("specify", specify);
        jsonObject.put("queryType", queryType);
        if (isParamLegal(dataTypes)) {
            jsonObject.put("dataTypes", dataTypes);
        }
        if (isParamLegal(show)) {
            jsonObject.put("show", show);
        }
        params.put("postStr", jsonObject.toString());
        params.put("type", "query");
        params.put("tk", key);
        String response = get(url, params);
        return response;
    }


    /**
     * @param keyWord   搜索的关键字
     * @param specify   指定行政区的国标码（行政区划编码表）严格按照行政区划编码表中的（名称，gb码）	下载行政区划编码表。9位国标码，如：北京：156110000。
     * @param queryType 服务查询类型参数	14：统计搜索服务。
     * @param dataTypes 数据分类（分类编码表）	下载分类编码表，参数可以分类名称或分类编码。多个分类用","隔开(英文逗号)。
     * @param show      返回poi结果信息类别	取值为1，则返回基本poi信息；取值为2，则返回详细poi信息
     * @return
     */
    public List<Poi> searchStatistics2(String keyWord, String specify, String queryType, String dataTypes, String show) throws Exception {
//
        String response = searchStatistics(keyWord, specify, queryType, dataTypes, show);
        return response2Pois(response);
    }

    private List<Poi> response2Pois(String response) throws Exception {
        List<Poi> pois = new ArrayList<>();
        //
        JSONObject jsonObject = new JSONObject(response);
        JSONObject status = jsonObject.getJSONObject("status");
        int infocode = status.getInt("infocode");
        if (infocode == 1000) {
            JSONArray jsonArray = jsonObject.getJSONArray("pois");
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject poi = jsonArray.getJSONObject(i);
                Gson gson = new Gson();
                pois.add(gson.fromJson(poi.toString(), Poi.class));
            }
        } else {
            String cndesc = status.getString("cndesc");
            throw new Exception("搜索异常 ： " + cndesc);
        }

        return pois;
    }


    public class Poi implements Serializable {
        private String eaddress;
        private String address;
        private String city;
        private String provinceCode;
        private String cityCode;
        private String county;
        private String typeName;
        private String source;
        private String typeCode;
        private String lonlat;
        private String countyCode;
        private String ename;
        private String province;
        private String phone;
        private String poiType;
        private String name;
        private String hotPointID;

        public String getEaddress() {
            return eaddress;
        }

        public void setEaddress(String eaddress) {
            this.eaddress = eaddress;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public String getProvinceCode() {
            return provinceCode;
        }

        public void setProvinceCode(String provinceCode) {
            this.provinceCode = provinceCode;
        }

        public String getCityCode() {
            return cityCode;
        }

        public void setCityCode(String cityCode) {
            this.cityCode = cityCode;
        }

        public String getCounty() {
            return county;
        }

        public void setCounty(String county) {
            this.county = county;
        }

        public String getTypeName() {
            return typeName;
        }

        public void setTypeName(String typeName) {
            this.typeName = typeName;
        }

        public String getSource() {
            return source;
        }

        public void setSource(String source) {
            this.source = source;
        }

        public String getTypeCode() {
            return typeCode;
        }

        public void setTypeCode(String typeCode) {
            this.typeCode = typeCode;
        }

        public String getLonlat() {
            return lonlat;
        }

        public void setLonlat(String lonlat) {
            this.lonlat = lonlat;
        }

        public String getCountyCode() {
            return countyCode;
        }

        public void setCountyCode(String countyCode) {
            this.countyCode = countyCode;
        }

        public String getEname() {
            return ename;
        }

        public void setEname(String ename) {
            this.ename = ename;
        }

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public String getPhone() {
            return phone;
        }

        public void setPhone(String phone) {
            this.phone = phone;
        }

        public String getPoiType() {
            return poiType;
        }

        public void setPoiType(String poiType) {
            this.poiType = poiType;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getHotPointID() {
            return hotPointID;
        }

        public void setHotPointID(String hotPointID) {
            this.hotPointID = hotPointID;
        }
    }


}
